﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;
using Microsoft.Xna.Framework;

namespace BGSpaceShooterServer
{
    internal class PlayerManager
    {
        private int maxPlayers;
        private List<Player> players;
        private XDocument document;

        public PlayerManager(int maxPlayers)
        {
            this.maxPlayers = maxPlayers;
            players = new List<Player>();
#if DEBUG
            document =
                XDocument.Load(
                    ".\\..\\..\\..\\BGSpaceShooter\\bin\\x86\\Debug\\Content\\Resources\\StarFighterStats.xml");
#else
            document = XDocument.Load(".\\Content\\Resources\\StarFighterStats.xml");
#endif
        }

        private bool IsFull()
        {
            return players.Where(s => s.Active && s.PlayerType == UserType.Player).Count() >= maxPlayers;
        }

        /// <summary>
        /// Dodaje gracza do zbioru uczestniczacych w grze
        /// </summary>
        /// <param name="player">Nowy gracz</param>
        /// <returns>ID przydzielone nowemu graczowi lub -1 gdy osiągnięto maksymalną liczbę graczy</returns>
        public int AddPlayer(Player player)
        {
            lock (players)
            {
                if (IsFull())
                {
                    Logger.Log(this, "Room is full.\n");
                    return -1;
                }
                else
                {

                    player.PlayerID = players.Count;
                    player.Reset();
                    players.Add(player);
                    Logger.Log(this, "New player [" + player.PlayerAddress.ToString() + " : " + player.PlayerPort + "] joined the game.\n");
                    return player.PlayerID;
                }
            }
        }

        /// <summary>
        /// Populates player class
        /// </summary>
        /// <param name="clientToServerPacket">Zgłoszenie klienta</param>
        /// <param name="address">Adres klienta</param>
        /// <returns>Populated Player</returns>
        public Player CreatePlayer(ClientToServerPacket clientToServerPacket, IPEndPoint address)
        {
            Player player = new Player();
            player.Active = true;
            player.PlayerAddress = address.Address;
            player.PlayerPort = address.Port;
            player.PlayerType = clientToServerPacket.PlayerType;

            StarFighter starFighter = new StarFighter();


            XElement element =
                document.Elements().Where(s => ushort.Parse(s.Attribute("ID").Value) == (ushort)clientToServerPacket.FighterType).First();

            starFighter.MaxHP = Int32.Parse(element.Attribute("HP").Value);
            starFighter.HP = starFighter.MaxHP;

            starFighter.MaxVelocity = new Vector3(float.Parse(element.Attribute("VelocityX").Value),
                                                  float.Parse(element.Attribute("VelocityY").Value),
                                                  float.Parse(element.Attribute("VelocityZ").Value));
            starFighter.Acceleration = new Vector3(float.Parse(element.Attribute("AccelerationX").Value),
                                                   float.Parse(element.Attribute("AccelerationY").Value),
                                                   float.Parse(element.Attribute("AccelerationZ").Value));
            starFighter.Rotation = Matrix.Identity;

            starFighter.BoundingSphere = new BoundingSphere(Vector3.Zero,
                                                            float.Parse(element.Attribute("Radius").Value));

            starFighter.StarFighterComponents = new List<StarFighterComponent>();

            foreach (XElement xElement in element.Elements("StarFighterComponent"))
            {
                StarFighterComponent fighterComponent = new StarFighterComponent();

                fighterComponent.MaxHP = Int32.Parse(xElement.Attribute("HP").Value);
                fighterComponent.HP = fighterComponent.MaxHP;
                fighterComponent.ID = Int32.Parse(xElement.Attribute("ID").Value);
                fighterComponent.MeshName = xElement.Value;
                fighterComponent.BoundingSphere =
                    new BoundingSphere(new Vector3(float.Parse(xElement.Attribute("CenterX").Value),
                                                   float.Parse(xElement.Attribute("CenterY").Value),
                                                   float.Parse(xElement.Attribute("CenterZ").Value)),
                                       float.Parse(xElement.Attribute("Radius").Value));

                starFighter.StarFighterComponents.Add(fighterComponent);
            }

            player.StarFighter = starFighter;

            return player;
        }

        /// <summary>
        /// Oznacza gracza jako nieaktywnego.
        /// </summary>
        /// <param name="playerID">ID gracza rezygnujacego z gry/wyrzucanego z gry</param>
        public void RemovePlayer(int playerID)
        {
            players[playerID].Active = false;
            Logger.Log(this, "Player [" + players[playerID].PlayerAddress.ToString() + "] left the game [ping timeout].\n");
        }

        public Player[] GetActivePlayers()
        {
            return players.Where(s => s.Active).ToArray();
        }

        public IEnumerable<Player> GetListOfActivePlayers()
        {
            return players.Where(s => s.Active);
        }

        public Player GetPlayerByID(int playerID)
        {
            if (playerID >= players.Count)
            {
                throw new Exception("Invalid PlayerID");
            }
            return players[playerID];
        }
    }
}
